namespace Org.Loon.Framework.Xna.Game.Action.Scripting
{
    using System;
    using System.Collections.Generic;
    using Org.Loon.Framework.Xna.Game.Core.Graphics;
    using Org.Loon.Framework.Xna.Game.Core.Timer;
    using Org.Loon.Framework.Xna.Game.Action.Scripting.Pack;
    using Org.Loon.Framework.Xna.Game.Core.Geom;
    using Org.Loon.Framework.Xna.Game.Core.Graphics.OpenGL;
    using Org.Loon.Framework.Xna.Game.Utils;
    using Org.Loon.Framework.Xna.Game.Action.Map;
    using Org.Loon.Framework.Xna.Game.Core.Input;
    using Org.Loon.Framework.Xna.Java;

    public abstract class ScriptScreen : Screen
    {

        public sealed class Go
        {

            internal LTimer timer = new LTimer(0);

            internal float speed = 1.5f;

            internal int direction;

            internal bool isComplete;

            internal PackSprite sprite;

            internal List<Vector2f> findPath;

            internal float startX, startY, endX, endY, moveX, moveY;

            public bool IsComplete()
            {
                return findPath == null || findPath.Count == 0 || isComplete;
            }

            public int GetWidth()
            {
                if (sprite != null)
                {
                    return sprite.GetWidth();
                }
                return 0;
            }

            public int GetHeight()
            {
                if (sprite != null)
                {
                    return sprite.GetHeight();
                }
                return 0;
            }

            public void Update()
            {
                if (sprite != null)
                {
                    sprite.SetLocation(startX, startY);
                    sprite.SetDirection(direction);
                }
            }

        }

        private Dictionary<PackSprite, Go> paths;

        private string packName, mapName;

        private string scriptFile;

        private ScriptFactory scripts;

        private PackSprites packSprites;

        private Callback callback;

        private PackView view;

        private LTexturePack tempPack;

        private PackTileMap tempMap;

        private bool isPack, isMap;

        private PackTileFactory tileFactory;

        public ScriptScreen(string res)
        {
            if (res == null)
            {
                throw new RuntimeException("script name is null !");
            }
            this.scriptFile = res;
        }

        public override void OnCreate(int width, int height)
        {
            base.OnCreate(width, height);
            this.isPack = false;
            this.isMap = false;
            if (paths != null)
            {
                paths.Clear();
                paths = null;
            }
            this.paths = new Dictionary<PackSprite, Go>(10);
            if (packSprites != null)
            {
                packSprites.Clear();
                packSprites = null;
            }
            this.packSprites = new PackSprites();
            if (scripts != null)
            {
                scripts.Clear();
                scripts = null;
            }
            this.scripts = new ScriptFactory(this, scriptFile);
        }

        public Callback GetCallback()
        {
            return callback;
        }

        public void SetCallback(Callback callback)
        {
            this.callback = callback;
            if (scripts != null)
            {
                scripts.SetCallback(callback);
            }
        }

        public Callback OnCallback()
        {
            return null;
        }

        public override void OnLoad()
        {
            if (scripts != null)
            {
                scripts.Load();
                packName = scripts.getPackName();
                mapName = scripts.getMapName();
                OnLoading();
            }
        }

        public Go GetGo(PackSprite sprite)
        {
            Go go = (Go)CollectionUtils.Get(paths, sprite);
            if (go != null)
            {
                return go;
            }
            return null;
        }

        public void StopMove(PackSprite sprite)
        {
            Go go = (Go)CollectionUtils.Get(paths, sprite);
            if (go != null)
            {
                go.isComplete = true;
            }
        }

        public void UpdateMoveSpeed(PackSprite sprite, float speed)
        {
            Go go = (Go)CollectionUtils.Get(paths, sprite);
            if (go != null)
            {
                go.speed = speed;
            }
        }

        public void UpdateMoveDelay(PackSprite sprite, long delay)
        {
            Go go = (Go)CollectionUtils.Get(paths, sprite);
            if (go != null)
            {
                go.timer.SetDelay(delay);
            }
        }

        public void ToMove(PackSprite sprite, AStarFindHeuristic heuristic,
                LTouch touch)
        {
            ToMove(sprite, heuristic, touch.X(), touch.Y(), true);
        }

        public void ToMove(PackSprite sprite, AStarFindHeuristic heuristic,
                LTouch touch, bool flag)
        {
            ToMove(sprite, heuristic, touch.X(), touch.Y(), flag);
        }

        public void ToMove(PackSprite sprite, AStarFindHeuristic heuristic, int x,
                int y)
        {
            ToMove(sprite, heuristic, x, y, true);
        }

        public void ToMove(PackSprite sprite, AStarFindHeuristic heuristic, int x,
                int y, bool flag)
        {
            ToMove(sprite, heuristic, 0, 2f, x, y, flag);
        }

        public void ToMove(PackSprite sprite, AStarFindHeuristic heuristic,
                LTouch touch, float speed)
        {
            ToMove(sprite, heuristic, 0, speed, touch.X(), touch.Y(), true);
        }

        public void ToMove(PackSprite sprite, AStarFindHeuristic heuristic,
                long delay, float speed, LTouch touch)
        {
            ToMove(sprite, heuristic, delay, speed, touch.X(), touch.Y(), true);
        }

        public void ToMove(PackSprite sprite, AStarFindHeuristic heuristic,
                long delay, float speed, LTouch touch, bool flag)
        {
            ToMove(sprite, heuristic, delay, speed, touch.X(), touch.Y(), flag);
        }

        public void ToMove(PackSprite sprite, AStarFindHeuristic heuristic,
                long delay, float speed, int x, int y)
        {
            ToMove(sprite, heuristic, delay, speed, x, y, true);
        }

        public void ToMove(PackSprite sprite, AStarFindHeuristic heuristic,
                long delay, float speed, int x, int y, bool flag)
        {
            ToMove(FindAStar(heuristic, sprite.X(), sprite.Y(), x, y, flag),
                    sprite, delay, speed);
        }

        public void ToMove(List<Vector2f> path, PackSprite sprite,
                long delay, float speed)
        {
            lock (typeof(ScriptScreen))
            {
                Go go = (Go)CollectionUtils.Get(paths, sprite);
                if (go == null)
                {
                    go = new Go();
                    paths.Add(sprite, go);
                }
                if (go.findPath != null)
                {
                    go.findPath.Clear();
                }
                go.findPath = path;
                go.sprite = sprite;
                go.timer.SetDelay(delay);
                go.speed = speed;
            }
        }

        public List<Vector2f> FindAStar(AStarFindHeuristic heuristic, int x1,
                int y1, LTouch touch)
        {
            PackTileMap map = GetMap(mapName);
            if (map != null)
            {
                return map.FindAStar(heuristic, x1, y1, touch);
            }
            return null;
        }

        public List<Vector2f> FindAStar(AStarFindHeuristic heuristic, int x1,
                int y1, bool flag, LTouch touch)
        {
            PackTileMap map = GetMap(mapName);
            if (map != null)
            {
                return map.FindAStar(heuristic, x1, y1, flag, touch);
            }
            return null;
        }

        public List<Vector2f> FindAStar(AStarFindHeuristic heuristic, int x1,
                int y1, int x2, int y2)
        {
            PackTileMap map = GetMap(mapName);
            if (map != null)
            {
                return map.FindAStar(heuristic, x1, y1, x2, y2);
            }
            return null;
        }

        public List<Vector2f> FindAStar(AStarFindHeuristic heuristic, int x1,
                int y1, int x2, int y2, bool flag)
        {
            PackTileMap map = GetMap(mapName);
            if (map != null)
            {
                return map.FindAStar(heuristic, x1, y1, x2, y2, flag);
            }
            return null;
        }

        public void SetLimit(int[] list)
        {
            PackTileMap map = GetMap(mapName);
            if (map != null)
            {
                map.Limit(list);
            }
        }

        public int[] GetLimit()
        {
            PackTileMap map = GetMap(mapName);
            if (map != null)
            {
                return map.GetLimit();
            }
            return null;
        }

        public void SubMap(int x, int y, int w, int h)
        {
            PackTileMap map = GetMap(mapName);
            if (map != null)
            {
                map.Sub(x, y, w, h);
            }
        }

        public void SubMap(int x, int y)
        {
            PackTileMap map = GetMap(mapName);
            if (map != null)
            {
                map.Sub(x, y);
            }
        }

        public void SetMapPos(int x, int y)
        {
            PackTileMap map = GetMap(mapName);
            if (map != null)
            {
                map.SetPos(x, y);
            }
        }

        public PackSprite AddPackSprite(string name, long delay, float x, float y)
        {
            return AddPackSprite(name, GetAnimation(name), delay, x, y);
        }

        public PackSprite AddPackSprite(string name, float x, float y)
        {
            return AddPackSprite(name, GetAnimation(name), 150, x, y);
        }

        public PackSprite AddPackSprite(string name, PackAnimation animation,
                float x, float y)
        {
            return AddPackSprite(name, animation, 150, x, y);
        }

        public PackSprite AddPackSprite(string name, PackAnimation animation,
                long delay, float x, float y)
        {
            if (packSprites != null)
            {
                if (animation != null)
                {
                    PackSprite sprite = new PackSprite(animation);
                    packSprites.Add(sprite, x, y);
                    sprite.SetName(name);
                    sprite.SetDelay(delay);
                    return sprite;
                }
                else
                {
                    return null;
                }
            }
            return null;
        }

        public void RemovePackSprite(PackSprite sprite)
        {
            if (packSprites != null)
            {
                packSprites.Remove(sprite);
            }
        }

        public PackSprite FindPackSprite(string name)
        {
            return packSprites.Find(name);
        }

        public void SetMapBlockSize(int tileWidth, int tileHeight)
        {
            PackTileMap map = GetMap(mapName);
            if (map != null)
            {
                map.SetBlockSize(tileWidth, tileHeight);
            }
        }

        public int GetMapWidth()
        {
            PackTileMap map = GetMap(mapName);
            if (map != null)
            {
                return map.GetWidth();
            }
            return 0;
        }

        public int GetMapHeight()
        {
            PackTileMap map = GetMap(mapName);
            if (map != null)
            {
                return map.GetHeight();
            }
            return 0;
        }

        public PackTile GetTile(int x, int y)
        {
            PackTileMap map = GetMap(mapName);
            if (map != null)
            {
                return map.GetTile(x, y);
            }
            return null;
        }

        public void SetTile(int x, int y, PackTile type)
        {
            PackTileMap map = GetMap(mapName);
            if (map != null)
            {
                map.SetTile(x, y, type);
            }
        }

        public bool CollidesWith(PackSprite sprite)
        {
            return !CanMove(sprite, sprite.GetX(), sprite.GetY());
        }

        public int Count(PackTile element)
        {
            PackTileMap map = GetMap(mapName);
            if (map != null)
            {
                return map.Count(element);
            }
            return 0;
        }

        public bool CanMove(PackSprite sprite, float x, float y)
        {
            PackTileMap map = GetMap(mapName);
            if (map != null)
            {
                return map.CanMove(sprite, x, y);
            }
            return false;
        }

        public void Touch(PackSprite sprite)
        {
            PackTileMap map = GetMap(mapName);
            if (map != null)
            {
                map.Touch(sprite);
            }
        }

        public int GetTileWidth()
        {
            PackTileMap map = GetMap(mapName);
            if (map != null)
            {
                return map.GetTileWidth();
            }
            return 0;
        }

        public int GetTileHeight()
        {
            PackTileMap map = GetMap(mapName);
            if (map != null)
            {
                return map.GetTileHeight();
            }
            return 0;
        }

        public Field2D GetField2D()
        {
            PackTileMap map = GetMap(mapName);
            if (map != null)
            {
                return map.GetField2D();
            }
            return null;
        }

        public abstract void OnLoading();

        public override void OnLoaded()
        {
            if (callback == null)
            {
                callback = OnCallback();
            }
            if (scripts != null)
            {
                scripts.SetCallback(callback);
            }
            this.SetView(null);
            this.SetPackName(packName);
            this.SetMapName(mapName);
        }

        public void CallScript(string name)
        {
            if (scripts != null)
            {
                if (packSprites != null)
                {
                    packSprites.Clear();
                }
                scripts.Clear();
                scripts.Call(name);
            }
        }

        public void ClearScript()
        {
            if (scripts != null)
            {
                scripts.Clear();
            }
        }

        public void clearSprite()
        {
            if (packSprites != null)
            {
                packSprites.Clear();
            }
        }

        public void SetView(PackView view)
        {
            if (view == null)
            {
                view = PackView.EmptyView.GetInstance();
            }
            if (packSprites != null)
            {
                packSprites.SetView(view);
            }
            PackTileMap map = scripts.GetMap(mapName, tileFactory);
            if (map != null)
            {
                map.SetView(view);
            }
            this.view = view;
        }

        public PackView GetView()
        {
            return view;
        }

        public string GetMapName()
        {
            return mapName;
        }

        public void SetMapName(string name)
        {
            this.mapName = name;
            if (name != null && scripts != null)
            {
                this.scripts.SetMapName(name);
                this.mapName = name;
                this.tempMap = scripts.GetMap(mapName, tileFactory);
                if (tempMap != null)
                {
                    isMap = true;
                }
                else
                {
                    isMap = false;
                }
            }
        }

        public void SetPackName(string name)
        {
            if (name != null && scripts != null)
            {
                this.scripts.setPackName(name);
                this.packName = name;
                this.tempPack = scripts.GetPack(packName);
                if (tempPack != null)
                {
                    isPack = true;
                }
                else
                {
                    isPack = false;
                }
            }
        }

        public string GetPackName()
        {
            return this.packName;
        }

        public PackAnimation GetAnimation(string name)
        {
            return scripts.GetAnimation(name);
        }

        public LTexturePack GetPack(string name)
        {
            return scripts.GetPack(name);
        }

        public PackTileMap GetMap()
        {
            return GetMap(mapName);
        }

        public PackTileMap GetMap(string name)
        {
            return scripts.GetMap(name, tileFactory);
        }

        public Script GetScript(string name)
        {
            return scripts.GetScript(name);
        }

        private void Going()
        {
            if (!isMap)
            {
                return;
            }
            if (paths.Count > 0)
            {
                Field2D field2D = GetField2D();
                if (field2D == null)
                {
                    return;
                }
                lock (paths)
                {
                    foreach (Go go in paths.Values)
                    {
                        if (go == null || go.findPath == null)
                        {
                            continue;
                        }
                        if (go.IsComplete())
                        {
                            paths.Remove(go.sprite);
                            return;
                        }
                        if (go.timer.Action(elapsedTime))
                        {
                            lock (go.findPath)
                            {
                                if (go.endX == go.startX && go.endY == go.startY)
                                {
                                    if (go.findPath != null)
                                    {
                                        if (go.findPath.Count > 1)
                                        {
                                            Vector2f moveStart = (Vector2f)go.findPath
                                                    [0];
                                            Vector2f moveEnd = (Vector2f)go.findPath
                                                    [1];
                                            go.startX = field2D
                                                    .TilesToWidthPixels(moveStart
                                                            .X());
                                            go.startY = field2D
                                                    .TilesToHeightPixels(moveStart
                                                            .Y());
                                            go.endX = moveEnd.X()
                                                    * field2D.GetTileWidth();
                                            go.endY = moveEnd.Y()
                                                    * field2D.GetTileHeight();
                                            go.moveX = moveEnd.X() - moveStart.X();
                                            go.moveY = moveEnd.Y() - moveStart.Y();
                                            go.direction = Field2D.GetDirection(
                                                    (int)go.moveX, (int)go.moveY);
                                            go.findPath.RemoveAt(0);
                                        }
                                        else
                                        {
                                            go.findPath.Clear();
                                        }
                                    }
                                }
                                switch (go.direction)
                                {
                                    case Field2D.TUP:
                                        go.startY -= go.speed;
                                        if (go.startY < go.endY)
                                        {
                                            go.startY = go.endY;
                                        }
                                        break;
                                    case Field2D.TDOWN:
                                        go.startY += go.speed;
                                        if (go.startY > go.endY)
                                        {
                                            go.startY = go.endY;
                                        }
                                        break;
                                    case Field2D.TLEFT:
                                        go.startX -= go.speed;
                                        if (go.startX < go.endX)
                                        {
                                            go.startX = go.endX;
                                        }
                                        break;
                                    case Field2D.TRIGHT:
                                        go.startX += go.speed;
                                        if (go.startX > go.endX)
                                        {
                                            go.startX = go.endX;
                                        }
                                        break;
                                    case Field2D.UP:
                                        go.startX += go.speed;
                                        go.startY -= go.speed;
                                        if (go.startX > go.endX)
                                        {
                                            go.startX = go.endX;
                                        }
                                        if (go.startY < go.endY)
                                        {
                                            go.startY = go.endY;
                                        }
                                        break;
                                    case Field2D.DOWN:
                                        go.startX -= go.speed;
                                        go.startY += go.speed;
                                        if (go.startX < go.endX)
                                        {
                                            go.startX = go.endX;
                                        }
                                        if (go.startY > go.endY)
                                        {
                                            go.startY = go.endY;
                                        }
                                        break;
                                    case Field2D.LEFT:
                                        go.startX -= go.speed;
                                        go.startY -= go.speed;
                                        if (go.startX < go.endX)
                                        {
                                            go.startX = go.endX;
                                        }
                                        if (go.startY < go.endY)
                                        {
                                            go.startY = go.endY;
                                        }
                                        break;
                                    case Field2D.RIGHT:
                                        go.startX += go.speed;
                                        go.startY += go.speed;
                                        if (go.startX > go.endX)
                                        {
                                            go.startX = go.endX;
                                        }
                                        if (go.startY > go.endY)
                                        {
                                            go.startY = go.endY;
                                        }
                                        break;
                                }
                                go.Update();
                            }
                        }
                    }
                }
            }
        }

        public override void Alter(LTimerContext timer)
        {
            if (IsOnLoadComplete())
            {
                Going();
                scripts.Update();
                Update(timer.GetTimeSinceLastUpdate());
            }
        }

        public abstract void Update(long elapsedTime);

        public override void Draw(GLEx g)
        {
            if (IsOnLoadComplete())
            {
                if (isPack)
                {
                    if (isMap)
                    {
                        if (!tempMap.DrawSub(tempPack))
                        {
                            packSprites.Draw(tempPack, elapsedTime);
                            return;
                        }
                    }
                    if (packSprites.Size() > 0)
                    {
                        tempPack.GLBegin();
                        packSprites.Draw(tempPack, elapsedTime);
                        tempPack.GLEnd();
                    }
                }
                Paint(g);
            }
        }

        public abstract void Paint(GLEx g);

        public string GetScriptFile()
        {
            return scriptFile;
        }

        public void SetScriptFile(string script)
        {
            this.scriptFile = script;
        }

        public PackTileFactory GetTileFactory()
        {
            return tileFactory;
        }

        public void SetTileFactory(PackTileFactory tileFactory)
        {
            this.tileFactory = tileFactory;
            PackTileMap map = GetMap(mapName);
            if (map != null)
            {
                PackTileFactory factory = map.GetTileFactory();
                if (factory != null && !"simple".Equals(factory.GetName()))
                {
                    map.SetTileFactory(tileFactory);
                }
            }
        }

        public bool IsMap()
        {
            return isMap;
        }

        public bool IsPack()
        {
            return isPack;
        }

        public PackSprites GetPackSprites()
        {
            return packSprites;
        }

        public ScriptFactory GetScriptFactory()
        {
            return scripts;
        }

        public override void Dispose()
        {
            this.isPack = false;
            this.isMap = false;
            if (paths != null)
            {
                paths.Clear();
                paths = null;
            }
            if (scripts != null)
            {
                scripts.Dispose();
                scripts = null;
            }
            if (packSprites != null)
            {
                packSprites.Clear();
                packSprites = null;
            }
            if (paths != null)
            {
                paths.Clear();
                paths = null;
            }
        }

    }

}
